﻿Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.ComponentModel
Imports System.IO
Imports System.Drawing
Imports System.Drawing.Imaging

' To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
' <System.Web.Script.Services.ScriptService()> _
<System.Web.Services.WebService(Namespace:="http://tempuri.org/")> _
<System.Web.Services.WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<ToolboxItem(False)> _
Public Class PhotoService
    Inherits System.Web.Services.WebService

    Private thumbnailWidth As Integer = 60
    Private thumbnailHeight As Integer = 60

    Private webRoot As String
    ' Private sourcePhotosRoot
    Private photoRoot As String
    Public Sub New()
        ' photoRoot = GetPhotoRoot()
        webRoot = AddBs(Server.MapPath("./"))

        ' todo: Need to change to have 2 folders: Source and Target - will read source images and see if scaled image exists in target, if not create. Similar to thumbnails
        ' Where the source photos are
        ' sourcePhotosRoot = System.Configuration.ConfigurationManager.AppSettings("SourcePhotosRoot")
        Integer.TryParse(System.Configuration.ConfigurationManager.AppSettings("ThumbnailHeight"), thumbnailHeight)
        Integer.TryParse(System.Configuration.ConfigurationManager.AppSettings("ThumbnailWidth"), thumbnailWidth)

        ' Where to put the resized photos
        photoRoot = Server.MapPath("~/photos")
        photoRoot = AddBs(photoRoot)
    End Sub


    <WebMethod()> _
    Public Function GetTree() As String
        ' Build hierarchy of folders
        Dim ret As New XElement("folders")
        BuildFolders(photoRoot, ret, True)
        Return ret.ToString(SaveOptions.DisableFormatting)
    End Function

    Private Sub BuildFolders(ByVal startDir As String, ByVal ret As XElement, Optional ByVal isroot As Boolean = False)
        Dim dirs As String() = Directory.GetDirectories(startDir)
        Array.Sort(dirs)
        Dim origRet = ret
        'If dirs.Count > 0 AndAlso Not isroot Then
        '    Dim subele As New XElement("folders")
        '    ret.Add(subele)
        '    ret = subele
        'End If
        For Each di In dirs
            If di.StartsWith(".") Then Continue For
            ' skip thumb folder
            If di.IndexOf("thumbnails", StringComparison.CurrentCultureIgnoreCase) <> -1 Then Continue For
            Dim newele As New XElement("folder", di.Replace(webRoot, String.Empty))
            ' add count attribute too 
            newele.Add(New XAttribute("count", GetFolderCount(di)))
            ret.Add(newele)
            BuildFolders(di, newele)
        Next
        ret = origRet
    End Sub


    'Private Function GetPhotoRoot() As String
    '    ' Used to have config setting. However, for now just require Photos sub-folder
    '    'Dim ret = System.Configuration.ConfigurationManager.AppSettings("PhotosFolder")
    '    Dim ret = Server.MapPath("photos")
    '    Return AddBs(ret)
    'End Function

    Private Function AddBs(ByVal Path As String) As String
        If Not Path.EndsWith("\") Then Path &= "\"
        Return Path
    End Function


    Private Function GetFolderCount(ByVal path As String) As Integer
        ' returns just count
        Return Directory.GetFiles(path, "*.jpg").Count
    End Function

    <WebMethod()> _
    Public Function GetFolderInfo(ByVal path As String) As String
        Dim ret As New XElement("files")
        ret.Add(New XAttribute("webroot", webRoot))
        ret.Add(New XAttribute("baseuri", photoRoot))

        For Each fi In Directory.GetFiles(webRoot & path, "*.*")
            ' todo: Need to change to have 2 folders: Source and Target - will read source images and see if scaled image exists in target, if not create. Similar to thumbnails
            AddFileInfo(fi, ret)
        Next
        Return ret.ToString(SaveOptions.DisableFormatting)
    End Function

    Private Sub AddFileInfo(ByVal fname As String, ByVal ret As XElement)

        Dim fi As New FileInfo(fname)
        Select Case fi.Extension.ToUpper
            Case ".JPG", ".PNG"
                Dim add As New XElement("image", ResolveUrl(fi.FullName))
                ret.Add(add)
                ' *_thumb.jpg
                Dim tname As String
                tname = fi.DirectoryName & "\thumbnails\" & fi.Name
                If Not File.Exists(tname) Then
                    tname = fi.DirectoryName & "\thumbnails\" & fi.Name.Replace(fi.Extension, String.Empty) & "_thumb" & fi.Extension
                End If
                If File.Exists(tname) Then
                    add.Add(New XAttribute("thumbnail", ResolveUrl(tname)))
                Else
                    ' Build thumbnail
                    Try
                        ' make sure folder exists
                        Dim tnDir As String = Path.GetDirectoryName(tname)
                        If Not Directory.Exists(tnDir) Then Directory.CreateDirectory(tnDir)
                        Dim tn As Bitmap = CreateThumbnail(fi.FullName, thumbnailWidth, thumbnailHeight)
                        tn.Save(tname)
                        add.Add(New XAttribute("thumbnail", ResolveUrl(tname)))
                    Finally
                    End Try
                End If

            Case "WMV"
                ' todo: handle videos

        End Select
    End Sub

    Private Function ResolveUrl(ByVal filePath As String) As String
        Dim path As String = filePath.Replace(webRoot, String.Empty)
        Dim svcRoot As String = HttpContext.Current.Request.Url.AbsoluteUri
        svcRoot = svcRoot.Substring(0, svcRoot.LastIndexOf("/") + 1)
        Dim url As String = svcRoot + path.Replace("\", "/")
        Return url

    End Function

    Public Shared Function CreateThumbnail(ByVal lcFilename As String, ByVal lnWidth As Integer, ByVal lnHeight As Integer) As Bitmap
        ' from http://www.west-wind.com/Weblog/posts/283.aspx 
        Dim bmpOut As System.Drawing.Bitmap = Nothing
        Try
            Dim loBMP As New Bitmap(lcFilename)
            Dim loFormat As ImageFormat = loBMP.RawFormat


            Dim lnRatio As Decimal
            Dim lnNewWidth As Integer = 0
            Dim lnNewHeight As Integer = 0


            '*** If the image is smaller than a thumbnail just return it
            If loBMP.Width < lnWidth AndAlso loBMP.Height < lnHeight Then
                Return loBMP
            End If



            If loBMP.Width > loBMP.Height Then
                lnRatio = CDec(lnWidth) / loBMP.Width
                lnNewWidth = lnWidth
                Dim lnTemp As Decimal = loBMP.Height * lnRatio
                lnNewHeight = CInt(lnTemp)
            Else
                lnRatio = CDec(lnHeight) / loBMP.Height
                lnNewHeight = lnHeight
                Dim lnTemp As Decimal = loBMP.Width * lnRatio
                lnNewWidth = CInt(lnTemp)
            End If


            ' System.Drawing.Image imgOut = 
            ' loBMP.GetThumbnailImage(lnNewWidth,lnNewHeight,
            ' null,IntPtr.Zero);

            ' *** This code creates cleaner (though bigger) thumbnails and properly
            ' *** and handles GIF files better by generating a white background for
            ' *** transparent images (as opposed to black)
            bmpOut = New Bitmap(lnNewWidth, lnNewHeight)
            Dim g As Graphics = Graphics.FromImage(bmpOut)

            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic

            g.FillRectangle(Brushes.White, 0, 0, lnNewWidth, lnNewHeight)
            g.DrawImage(loBMP, 0, 0, lnNewWidth, lnNewHeight)


            loBMP.Dispose()
        Catch
            Return Nothing
        End Try

        Return bmpOut
    End Function

End Class